﻿/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

Author:       François PIETTE @ Balteau-NDT
Creation:     Feb 11, 2015
Description:  Demo showing how to automate Balteau NDT control Balteau-NDT
              applications using a TCP/IP connection.
              This source is a class specialized to control the X generator
              application (XRayRemoteControl.exe).  
Version:      1.00
Legal issues: This software is Open Source and subject to "The MIT License (MIT)"
              Copyright (C) 2015 Balteau-NDT
              Rue Voie de Liège 12, 4681 Hermalle Ss Argenteau, Belgium
              http://www.balteau-ndt.com
 
              Permission is hereby granted, free of charge, to any person 
              obtaining a copy of this software and associated documentation
              files (the "Software"), to deal in the Software without 
              restriction, including without limitation the rights to use, 
              copy, modify, merge, publish, distribute, sublicense, and/or 
              sell copies of the Software, and to permit persons to whom 
              the Software is furnished to do so, subject to the following 
              conditions:

              The above copyright notice and this permission notice shall 
              be included in all copies or substantial portions of the Software.

              THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
              EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
              OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
              NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
              HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
              WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
              OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
              DEALINGS IN THE SOFTWARE.

History:


 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Collections;
using System.Text;
using Balteau;

namespace Balteau
{
    // XRayCnxStatus represents the connections status to an XRay generator
    public class XRayCnxStatus
    {
        public enum CnxStatus {xrcsDISCONNECTED,  // Not connected yet
                               xrcsRMCACCEPTED,   // Remote mode accepted
                               xrcsCONNECTED};    // Connected
        public CnxStatus Value;
        public void FromString(string S)
        {
            foreach (CnxStatus cnxStatus in Enum.GetValues(typeof(CnxStatus))) {
                if (string.Equals(cnxStatus.ToString(), S)) {
                    Value = cnxStatus;
                    return;
                }
            }
            Value = CnxStatus.xrcsDISCONNECTED;
        }
    }

    // XRayFocusType represents a focus (filament)
    public class XRayFocusType
    {
        public enum Focus {xrftLARGE,   // Large filament
                           xrftSMALL,   // Small filament
                           xrftUNK};    // Unknown filament
        public Focus Value;
        public void FromString(string S)
        {
            foreach (Focus focus in Enum.GetValues(typeof(Focus))) {
                if (string.Equals(focus.ToString(), S)) {
                    Value = focus;
                    return;
                }
            }
            Value = Focus.xrftUNK;
        }
    }

    // XRayStatus represents the status of an XRay generator
    public class XRayStatus
    {
        public enum Status {xrsSTBRDY,        // Ready to start exposure
                            xrsSTBPRH,        // Ready to start preheating
                            xrsXON,           // Exposure (X-ray On)
                            xrsPRH,           // Preheating On (X-ray On)
                            xrsPREAL,         // Prealarm On
                            xrsERR,           // Error, X-ray stopped
                            xrsUNKNOWN,       // Other errors
                            xrsSTBPRHF};      // Ready to start forced preheating
        public Status Value;
        public void FromString(string S)
        {
            foreach (Status status in Enum.GetValues(typeof(Status))) {
                if (string.Equals(status.ToString(), S)) {
                    Value = status;
                    return;
                }
            }
            Value = Status.xrsUNKNOWN;
        }
        public override string ToString()
        {
            return Value.ToString();
        }
    }

    // XRayError represents the error codes returned by an XRay generator
    public class XRayError
    {
        public enum Error {// Common error (LS1/DC1/RC7)
                           xreEMERG,         // Emergency stop
                           xreDOOR,          // Door opened
                           xreNOERROR,       // No Error
                           xreWATER,         // Water cooling unit error
                           xreKEYOFF,        // Key in wrong position
                           xreGENLINK,       // No communication to generator
                           xreINTERR,        // Internal error
                           xreINVTEMP,       // Inverter high temperature
                           xreERRWD,         // Watchdog error
                           xreCLX,           // Clignotix error
                           xrePOWREL,        // Power relay error
                           xreUNKNOWN,       // Other errors
                           // DC1 specific error
                           xreTEMP_TUBE_HIGH,
                           xrePRESSURE_CUVE_LOW,
                           xrePRESSURE_CUVE_HIGH,
                           xreCHOPPER_FAIL,
                           xreHEATING_FAIL,
                           xreSTOP_TLCMD,
                           xre24V_LOW,
                           xreMAINS_FAIL,
                           xreI_MAX_CLIG_EXT,
                           xreTEMP_BUCK_HIGH,
                           xreTEMP_VALISE_HIGH,
                           xreVCC_ERROR,
                           xreVCC_SECURITY,
                           xreMA_HIGH,
                           xreMA_LOW,
                           xreKV_HIGH,
                           xreKV_LOW,
                           xreCONNECT_GEN_FAIL,
                           // RC7 specific error
                           xreSEC,            // A security is active
                           // LS1C2 specific error
                           xrePOWER_OFF}; 
        public Error Value;
        public void FromString(string S)
        {
            foreach (Error error in Enum.GetValues(typeof(Error))) {
                if (string.Equals(error.ToString(), S)) {
                    Value = error;
                    return;
                }
            }
            Value = Error.xreUNKNOWN;
        }
        public override string ToString()
        {
            return Value.ToString();
        }
    }

    public class KVUpdateEventArgs : EventArgs
    {
        public KVUpdateEventArgs(int aKV)
        {
            kv = aKV;
        }
        public int kv { get; set; }
    }

    public class MAUpdateEventArgs : EventArgs
    {
        public MAUpdateEventArgs(double aMA)
        {
            ma = aMA;
        }
        public double ma { get; set; }
    }

    public class GenStatusUpdateEventArgs : EventArgs
    {
        public GenStatusUpdateEventArgs(XRayStatus aStatus)
        {
            status = aStatus;
        }
        public XRayStatus status { get; set; }
    }

    public class GenErrorUpdateEventArgs : EventArgs
    {
        public GenErrorUpdateEventArgs(XRayError aError)
        {
            error = aError;
        }
        public XRayError error { get; set; }
    }

    public delegate void KVUpdateEventHandler(object sender, KVUpdateEventArgs e);
    public delegate void MAUpdateEventHandler(object sender, MAUpdateEventArgs e);
    public delegate void GenStatusUpdateEventHandler(object sender, GenStatusUpdateEventArgs e);
    public delegate void GenErrorUpdateEventHandler(object sender, GenErrorUpdateEventArgs e);

    public class XRayRemoteClientTcp : RemoteClientBaseTcp
    {
        public event KVUpdateEventHandler        KVUpdate;
        public event MAUpdateEventHandler        MAUpdate;
        public event GenStatusUpdateEventHandler GenStatusUpdate;
        public event GenErrorUpdateEventHandler  GenErrorUpdate;
         
        public    int           kvMax             = 0;
        public    int           kvRead            = 0;
        public    double        maRead            = 0;
        public    int           kvSet             = 0;
        public    double        maSet             = 0;
        public    int           prhTime           = 0;
        public    string        tubeName          = string.Empty;
        public    string        tubeSN            = string.Empty;
        public    int           focusCount        = 0;
        public    XRayStatus    genStatus         = new XRayStatus();
        public    XRayError     genError          = new XRayError();
        public    XRayFocusType focusSet          = new XRayFocusType();
        public    XRayCnxStatus connStatus        = new XRayCnxStatus();

        // Default constructor.
        public XRayRemoteClientTcp()
        {
        }

        // XRayRemoteControl send notification message. The method parses the
        // message and takes appropriate actions.
        protected override void ProcessNotification(string aParams)
        {
            bool   status = false;
            int    bufInt;
            double bufFloat;
            string bufString;

            string kind = ParamParsing.ParamByNameAsString(aParams, "Kind", ref status, "");

            if (string.Equals(kind, "KVRead")) {
                bufInt = ParamParsing.ParamByNameAsInteger(aParams, "KVRead", ref status, 0);
                if (status) {
                    kvRead = bufInt;
                    if (KVUpdate != null)
                        KVUpdate(this, new KVUpdateEventArgs(kvRead));
                }
            }
            else if (string.Equals(kind, "MARead")) {
                bufFloat = ParamParsing.ParamByNameAsFloat(aParams, "MARead", ref status, 0);
                if (status) {
                    maRead = bufFloat;
                    if (MAUpdate != null)
                        MAUpdate(this, new MAUpdateEventArgs(maRead));
                }
            }
            else if (string.Equals(kind, "GenStatus")) {
                bufString = ParamParsing.ParamByNameAsString(aParams, "GenStatus", ref status, "");
                if (status) {
                    genStatus.FromString(bufString);
                    if (GenStatusUpdate != null)
                        GenStatusUpdate(this, new GenStatusUpdateEventArgs(genStatus));
                }
            }
            else if (string.Equals(kind, "GenError")) {
                bufString = ParamParsing.ParamByNameAsString(aParams, "GenError", ref status, "");
                if (status) {
                    genError.FromString(bufString);
                    if (GenErrorUpdate != null)
                        GenErrorUpdate(this, new GenErrorUpdateEventArgs(genError));
                }
            }
        }

        protected override void ProcessResponseOfCommand(int respCode, string respMsg)
        {
            // Disptach response processing to specialized methods.
            if (string.Equals(commandExecuting.cmd, "GetState"))
                ProcessResponseOfCommandGetState(respCode, respMsg);
            // You can add more response decoding if you need it

            // Handle response processing as specified in the base class.
            // This will among other things trigger the CommandDone event.
            base.ProcessResponseOfCommand(respCode, respMsg);
        }
        
        // Process the response received from a "GetState" command.
        protected void ProcessResponseOfCommandGetState(int respCode, string respMsg)
        {
            bool status = false;
            string buf;

            if (respCode == 211) {
                kvSet  = ParamParsing.ParamByNameAsInteger(respMsg, "KVSet",     ref status, kvSet);
                maSet  = ParamParsing.ParamByNameAsFloat  (respMsg, "MaSet",     ref status, maSet);
                kvRead = ParamParsing.ParamByNameAsInteger(respMsg, "KVRead",    ref status, kvRead);
                maRead = ParamParsing.ParamByNameAsFloat  (respMsg, "MaRead",    ref status, maRead);
                kvMax  = ParamParsing.ParamByNameAsInteger(respMsg, "KVMax",     ref status, kvMax);
                buf    = ParamParsing.ParamByNameAsString (respMsg, "GenStatus", ref status, "");
                if (status)
                    genStatus.FromString(buf);
                buf    = ParamParsing.ParamByNameAsString (respMsg, "GenError", ref status, "");
                if (status)
                    genError.FromString(buf);
                buf    = ParamParsing.ParamByNameAsString (respMsg, "CnxStatus", ref status, "");
                if (status)
                    connStatus.FromString(buf);
            }
        }

        // Start XRay generator. Actually, this command is asynchronous.
        // It means it returns immediately, without waiting for the command
        // to be executed. To check the result, you must process the response,
        // see ProcessResponseOfCommand method.
        public bool StartX(string aParameters)
        {
            TriggerDisplay("XRay StartX");
            return QueueCmd("StartX", aParameters);
        }

        // Stop XRay generator. Actually, this command is asynchronous.
        // It means it returns immediately, without waiting for the command
        // to be executed. To check the result, you must process the response,
        // see ProcessResponseOfCommand method.
        public bool StopX()
        {
            return QueueCmd("StopX", "");
        }

        // Send kV and mA to generator. Actually, this command is asynchronous.
        // It means it returns immediately, without waiting for the command
        // to be executed. To check the result, you must process the response,
        // see ProcessResponseOfCommand method.
        public bool SetKVMA(int aKV, double aMA)
        {
            return QueueCmd("SetKVMA", "kV=" + aKV.ToString() + ";mA=" + ParamParsing.MyFloatToStr(aMA));
        }

        // Request generator state. Actually, this command is asynchronous.
        // It means it returns immediately, without waiting for the command
        // to be executed. To check the result, you must process the response,
        // see ProcessResponseOfCommand method.
        public bool GetState()
        {
            return QueueCmd("GetState", "");
        }
    }
}
